package com.zsk.gen;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CodeGen {

    GenConfig config = null;
    Connection conn = null;
    Statement st = null;

    public CodeGen(GenConfig config) {
        this.config = config;
    }

    /**
     * 初始化数据库连接
     */
    public void initConn() {
        try {
            Class.forName(config.getDrive()).newInstance();
            conn = java.sql.DriverManager.getConnection(config.getUrl(), config.getUser(), config.getPassword());
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    /**
     * 生成公共代码
     */
    public void commonGen() {
        new CommonGen(config).gen();
    }

    /**
     * 读取数据表
     * 
     * @param tableNames
     *            逆向表名
     * @param allTables
     *            逆向全部表
     * 
     */
    public void readTable(String[] tableNames, boolean all) {

        Set<String> tableNameSet = new HashSet<>(Arrays.asList(tableNames));
        // 表明和表注释
        Map<String, String> tableNameMap = new HashMap<>();
        try {

            DatabaseMetaData dbMetaData = conn.getMetaData();
            ResultSet rs = dbMetaData.getTables(null, null, null, new String[] {"TABLE"});
            while (rs.next()) {
                // 表名
                String name = rs.getString("TABLE_NAME");
                // 表备注
                String note = rs.getString("REMARKS");
                // 保存满足条件的表
                if (all || tableNameSet.contains(name)) {
                    tableNameMap.put(name, note);
                }
                // sbTables.append("表名：" + rs.getString("TABLE_NAME") + "\n");
                // sbTables.append("表类型：" + rs.getString("TABLE_TYPE") + "\n");
                // sbTables.append("表所属数据库：" + rs.getString("TABLE_CAT") + "\n");
                // sbTables.append("表所属用户名：" + rs.getString("TABLE_SCHEM") + "\n");
                // sbTables.append("表备注：" + rs.getString("REMARKS") + "\n");
                // sbTables.append("------------------------------\n");

            }

            if (!all) {
                for (String inputName : tableNames) {
                    if (!tableNameMap.containsKey(inputName)) {
                        throw new RuntimeException("表" + inputName + "不存在");
                    }
                }

            }

            readTableDetail(tableNameMap);

        } catch (SQLException e) {
            log.error(e.toString());
        }

    }

    /**
     * 读取表具体信息
     * 
     * @param tableNames
     */
    public void readTableDetail(Map<String, String> tableMap) {
        Set<String> set = tableMap.keySet();
        for (String tableName : set) {

            // 获取字段注释
            Map<String, String> commentMap = new HashMap<>();
            try {
                ResultSet res = conn.getMetaData().getColumns(null, null, tableName.toUpperCase(), "%");
                while (res.next()) {
                    String colName = res.getString("COLUMN_NAME");
                    String remarks = res.getString("REMARKS");
                    commentMap.put(colName, remarks);
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            // 获取字段属性
            String sql = "select * from " + tableName + " limit 1";
            try {

                PreparedStatement ps = conn.prepareStatement(sql);
                ResultSet rs = ps.executeQuery();
                ResultSetMetaData meta = rs.getMetaData();
                int columeCount = meta.getColumnCount();
                log.debug("表 " + tableName + "共有 " + columeCount + " 个字段。字段信息如下：");
                List<EntityProperty> list = new ArrayList<>();

                for (int i = 1; i < columeCount + 1; i++) {
                    // //il - 字段名：name
                    // 13:50:04.853 [main] DEBUG com.zsk.gen.DataBaseUtil - 类型：12
                    // 13:50:04.853 [main] DEBUG com.zsk.gen.DataBaseUtil - 类型：VARCHAR
                    // 13:50:04.853 [main] DEBUG com.zsk.gen.DataBaseUtil - CatalogName：test_db
                    // 13:50:04.853 [main] DEBUG com.zsk.gen.DataBaseUtil - getColumnClassName：java.lang.String
                    // 13:50:04.853 [main] DEBUG com.zsk.gen.DataBaseUtil - getColumnLabel：name
                    // log.debug("字段名：" + meta.getColumnName(i));
                    log.debug("类型：" + meta.getColumnType(i));
                    log.debug("类型：" + meta.getColumnTypeName(i));
                    log.debug("CatalogName：" + meta.getCatalogName(i));
                    log.debug("getColumnClassName：" + meta.getColumnClassName(i));
                    log.debug("getColumnLabel：" + meta.getColumnLabel(i));
                    log.debug("------------------------------");
                    //
                    // log.debug("------------------------------");

                    EntityProperty entity = new EntityProperty();
                    entity.setName(meta.getColumnName(i));
                    entity.setClassName(meta.getColumnClassName(i));
                    entity.setType(entity.getClassName().substring(entity.getClassName().lastIndexOf(".") + 1));
                    entity.setComment(commentMap.get(meta.getColumnName(i)));
                    list.add(entity);
                }
                String tableComment = tableMap.get(tableName);
                if (config.isGenEntity()) {
                    new EntityGen(tableName, tableMap.get(tableName), list, config).gen();
                }
                if (config.isGenRepository()) {
                    new RepositoryGen(tableName, tableComment, config).gen();
                }
                if (config.isGenService()) {
                    new ServiceGen(tableName, tableComment, config).gen();
                }

            } catch (SQLException e) {
                log.error(e.toString());
            }
        }

    }

    // 释放conn
    public void releaseConn() {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                log.error(e.toString());
            }
        }
    }

    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(tip);
        String input = "";
        while (scanner.hasNextLine()) {
            input = scanner.nextLine();
            if (!"".equals(input.trim())) {
                scanner.close();
                break;
            }
        }
        return input;
    }

    public static void main(String[] args) {

        // 创建配置文件
        GenConfig config = new GenConfig();
        // 作者
        config.setAuthor("keke");
        // 根包名
        config.setBasePackage("com.zsk");
        // 模块名
        config.setModuleName("test");
        // 覆盖已有代码
        config.setCoverCode(true);
        // 若要读取到表备注要加useInformationSchema=true
        // mysql url
        config.setUrl(
            "jdbc:mysql://localhost:3306/test_db?characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false&useInformationSchema=true");
        // mysql驱动
        config.setDrive("com.mysql.jdbc.Driver");
        // mysql用户名
        config.setUser("amsuser");
        // mysql密码
        config.setPassword("ams2018");

        CodeGen gen = new CodeGen(config);
        gen.initConn();

        String tableName = scanner("请输入表名，多个表用逗号分隔：\n");

        // 第二个参数表示是否全部逆向数据库中的表
        gen.readTable(tableName.split(","), false);
        gen.commonGen();
        gen.releaseConn();
    }

}
